package com.thz.system.utils.svg;

import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SVG压缩工具类
 * 使用Python的scour库或内置方法压缩SVG文件
 *
 * @author THZ
 * @date 2025
 */
@Slf4j
@Component
public class SvgCompressor {

    @Value("${matting.python.path:python}")
    private String pythonPath;

    /**
     * 压缩SVG文件
     *
     * @param inputSvgPath 输入SVG文件路径
     * @param outputSvgPath 输出SVG文件路径
     * @return 压缩后的文件大小（字节）
     */
    public long compressSvg(String inputSvgPath, String outputSvgPath) {
        if (outputSvgPath == null) {
            outputSvgPath = inputSvgPath;
        }

        long startTime = System.currentTimeMillis();
        File inputFile = new File(inputSvgPath);
        if (!inputFile.exists()) {
            throw new BusinessException(ErrorCode.FILE_NOT_FOUND, "SVG文件不存在: " + inputSvgPath);
        }

        long originalSize = inputFile.length();
        log.info("开始压缩SVG: {} (原始大小: {} KB)", inputSvgPath, originalSize / 1024.0);

        try {
            // 优先尝试使用scour库压缩
            if (isScourAvailable()) {
                log.info("使用scour库进行高质量压缩");
                compressWithScour(inputSvgPath, outputSvgPath);
            } else {
                log.info("scour库不可用，使用内置压缩方法");
                compressWithBuiltIn(inputSvgPath, outputSvgPath);
            }

            File outputFile = new File(outputSvgPath);
            long compressedSize = outputFile.length();
            double compressionRatio = (1.0 - (double) compressedSize / originalSize) * 100;
            long duration = System.currentTimeMillis() - startTime;

            log.info("SVG压缩完成: 原始大小={} KB, 压缩后={} KB, 压缩率={}%, 耗时={}ms",
                    String.format("%.2f", originalSize / 1024.0),
                    String.format("%.2f", compressedSize / 1024.0),
                    String.format("%.2f", compressionRatio), duration);

            return compressedSize;

        } catch (Exception e) {
            log.error("SVG压缩失败，使用原文件", e);
            // 如果压缩失败，复制原文件到输出路径
            try {
                if (!inputSvgPath.equals(outputSvgPath)) {
                    java.nio.file.Files.copy(inputFile.toPath(), new File(outputSvgPath).toPath());
                }
            } catch (IOException ex) {
                log.error("复制原文件失败", ex);
            }
            return originalSize;
        }
    }

    /**
     * 使用scour库压缩SVG（高质量）
     */
    private void compressWithScour(String inputPath, String outputPath) throws IOException, InterruptedException {
        String pythonScript = buildScourCompressionScript(inputPath, outputPath);
        executePythonScript(pythonScript);

        File outputFile = new File(outputPath);
        if (!outputFile.exists() || outputFile.length() == 0) {
            throw new IOException("scour压缩失败，输出文件无效");
        }
    }

    /**
     * 使用内置方法压缩SVG（基础优化）
     */
    private void compressWithBuiltIn(String inputPath, String outputPath) throws IOException {
        // 读取SVG内容
        String svgContent;
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(inputPath), StandardCharsets.UTF_8))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line.trim());
            }
            svgContent = sb.toString();
        }

        // 基础优化：移除多余空白、优化属性
        svgContent = optimizeSvgContent(svgContent);

        // 写入压缩后的内容
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(outputPath), StandardCharsets.UTF_8))) {
            writer.write(svgContent);
        }
    }

    /**
     * 优化SVG内容（内置方法）
     */
    private String optimizeSvgContent(String svg) {
        // 移除XML声明中的多余空白
        svg = svg.replaceAll("\\s+", " ");

        // 移除属性值前后的空白
        svg = svg.replaceAll("\\s*=\\s*", "=");
        svg = svg.replaceAll("\\s*>", ">");
        svg = svg.replaceAll("<\\s*", "<");

        // 移除注释（如果存在）
        svg = svg.replaceAll("<!--.*?-->", "");

        // 优化路径数据：移除多余空格
        Pattern pathPattern = Pattern.compile("(d=\"[^\"]*\")");
        Matcher pathMatcher = pathPattern.matcher(svg);
        StringBuffer sb = new StringBuffer();
        while (pathMatcher.find()) {
            String pathData = pathMatcher.group(1);
            // 优化路径数据
            pathData = pathData.replaceAll("\\s+", " ");
            pathData = pathData.replaceAll("\\s*([MmLlHhVvCcSsQqTtAaZz])\\s*", "$1");
            pathMatcher.appendReplacement(sb, Matcher.quoteReplacement(pathData));
        }
        pathMatcher.appendTail(sb);
        svg = sb.toString();

        // 移除标签之间的空白
        svg = svg.replaceAll(">\\s+<", "><");

        return svg;
    }

    /**
     * 构建scour压缩脚本
     */
    private String buildScourCompressionScript(String inputPath, String outputPath) {
        StringBuilder s = new StringBuilder();
        s.append("# -*- coding: utf-8 -*-\n");
        s.append("import sys\n");
        s.append("import io\n");
        s.append("\n");
        s.append("# 设置标准输出为 UTF-8 编码\n");
        s.append("sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')\n");
        s.append("sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')\n");
        s.append("\n");
        s.append("# 尝试导入scour库（支持多种导入方式）\n");
        s.append("scourString = None\n");
        s.append("ScourOptions = None\n");
        s.append("try:\n");
        s.append("    import scour\n");
        s.append("    from scour.scour import scourString\n");
        s.append("    try:\n");
        s.append("        from scour.scour import ScourOptions\n");
        s.append("    except ImportError:\n");
        s.append("        pass  # ScourOptions可能不存在，使用默认参数\n");
        s.append("except ImportError:\n");
        s.append("    try:\n");
        s.append("        from scour import scourString\n");
        s.append("        try:\n");
        s.append("            from scour import ScourOptions\n");
        s.append("        except ImportError:\n");
        s.append("            pass  # ScourOptions可能不存在，使用默认参数\n");
        s.append("    except ImportError:\n");
        s.append("        print('scour库未安装，请执行: pip install scour', file=sys.stderr)\n");
        s.append("        sys.exit(1)\n");
        s.append("\n");
        s.append("if scourString is None:\n");
        s.append("    print('无法导入scourString', file=sys.stderr)\n");
        s.append("    sys.exit(1)\n");
        s.append("\n");
        s.append("input_path = r'").append(inputPath.replace("\\", "\\\\")).append("'\n");
        s.append("output_path = r'").append(outputPath.replace("\\", "\\\\")).append("'\n");
        s.append("\n");
        s.append("try:\n");
        s.append("    # 读取SVG文件\n");
        s.append("    with open(input_path, 'r', encoding='utf-8') as f:\n");
        s.append("        svg_content = f.read()\n");
        s.append("    \n");
        s.append("    original_size = len(svg_content.encode('utf-8'))\n");
        s.append("    print(f'原始SVG大小: {original_size / 1024:.2f} KB')\n");
        s.append("    \n");
        s.append("    # 使用scour压缩（尝试使用ScourOptions，如果不可用则使用默认参数）\n");
        s.append("    if ScourOptions is not None:\n");
        s.append("        try:\n");
        s.append("            # 使用ScourOptions配置选项（新版本API）\n");
        s.append("            options = ScourOptions()\n");
        s.append("            options.remove_metadata = True\n");
        s.append("            options.remove_comments = True\n");
        s.append("            options.remove_editor_namespace = True\n");
        s.append("            options.remove_metadata_elements = True\n");
        s.append("            options.strip_ids = False  # 保留ID保证质量\n");
        s.append("            options.shorten_ids = True\n");
        s.append("            options.indent_type = None\n");
        s.append("            options.indent_depth = 0\n");
        s.append("            options.newlines = False\n");
        s.append("            options.strip_xml_prolog = False\n");
        s.append("            options.enable_viewboxing = True\n");
        s.append("            options.render_workaround = False\n");
        s.append("            options.digits = 3  # 数值精度（3位小数）\n");
        s.append("            options.strip_default_attributes = True\n");
        s.append("            options.remove_descriptive_elements = True\n");
        s.append("            options.keep_editor_data = False\n");
        s.append("            options.keep_unreferenced_defs = False\n");
        s.append("            options.strip_xml_space_attribute = True\n");
        s.append("            options.create_groups = False\n");
        s.append("            options.error_on_flowtext = False\n");
        s.append("            options.keep_titles = False\n");
        s.append("            options.keep_defs = True\n");
        s.append("            # 执行压缩（使用ScourOptions对象）\n");
        s.append("            compressed_svg = scourString(svg_content, options)\n");
        s.append("            print('使用ScourOptions进行压缩')\n");
        s.append("        except (TypeError, AttributeError) as e:\n");
        s.append("            # 如果ScourOptions API不可用，使用默认参数\n");
        s.append("            print(f'ScourOptions API不可用，使用默认参数: {e}')\n");
        s.append("            compressed_svg = scourString(svg_content)\n");
        s.append("    else:\n");
        s.append("        # ScourOptions不存在，使用默认参数\n");
        s.append("        print('ScourOptions不可用，使用默认参数压缩')\n");
        s.append("        compressed_svg = scourString(svg_content)\n");
        s.append("    \n");
        s.append("    # 写入压缩后的文件\n");
        s.append("    with open(output_path, 'w', encoding='utf-8') as f:\n");
        s.append("        f.write(compressed_svg)\n");
        s.append("    \n");
        s.append("    compressed_size = len(compressed_svg.encode('utf-8'))\n");
        s.append("    compression_ratio = (1.0 - compressed_size / original_size) * 100\n");
        s.append("    print(f'压缩后SVG大小: {compressed_size / 1024:.2f} KB')\n");
        s.append("    print(f'压缩率: {compression_ratio:.2f}%')\n");
        s.append("    print('[SUCCESS] SVG压缩完成')\n");
        s.append("    \n");
        s.append("except Exception as e:\n");
        s.append("    import traceback\n");
        s.append("    print(f'[ERROR] SVG压缩失败: {e}', file=sys.stderr)\n");
        s.append("    traceback.print_exc()\n");
        s.append("    sys.exit(1)\n");

        return s.toString();
    }

    /**
     * 执行Python脚本
     */
    private void executePythonScript(String pythonScript) throws IOException, InterruptedException {
        File tempScript = File.createTempFile("svg_compress_", ".py");
        tempScript.deleteOnExit();

        try (FileWriter writer = new FileWriter(tempScript, StandardCharsets.UTF_8)) {
            writer.write(pythonScript);
        }

        List<String> command = new ArrayList<>();
        command.add(pythonPath);
        command.add("-u");
        command.add(tempScript.getAbsolutePath());

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.redirectErrorStream(true);
        processBuilder.environment().put("PYTHONIOENCODING", "utf-8");

        Process process = processBuilder.start();

        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
                log.debug("Python输出: {}", line);
            }
        }

        int exitCode = process.waitFor();
        tempScript.delete();

        if (exitCode != 0) {
            throw new IOException("SVG压缩失败，退出码: " + exitCode + ", 错误: " + output.toString());
        }

        log.debug("Python压缩脚本输出: {}", output.toString());
    }

    /**
     * 检查scour库是否可用
     */
    public boolean isScourAvailable() {
        try {
            File tempTestScript = File.createTempFile("scour_test_", ".py");
            tempTestScript.deleteOnExit();

            String testCode =
                "try:\n" +
                "    import scour\n" +
                "    from scour.scour import scourString\n" +
                "    print('OK')\n" +
                "except ImportError:\n" +
                "    try:\n" +
                "        from scour import scourString\n" +
                "        print('OK')\n" +
                "    except ImportError:\n" +
                "        print('NOT_AVAILABLE')";

            try (FileWriter writer = new FileWriter(tempTestScript, StandardCharsets.UTF_8)) {
                writer.write(testCode);
            }

            List<String> command = new ArrayList<>();
            command.add(pythonPath);
            command.add(tempTestScript.getAbsolutePath());

            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true);
            Process process = processBuilder.start();

            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            int exitCode = process.waitFor();
            tempTestScript.delete();

            if (exitCode == 0 && output.toString().contains("OK")) {
                return true;
            } else {
                log.info("[INFO] scour库不可用 - 将使用内置压缩方法");
                log.info("[TIPS] 安装scour获得更好的压缩效果: pip install scour");
                return false;
            }
        } catch (Exception e) {
            log.warn("[WARN] 检查scour库失败: {} - 将使用内置压缩方法", e.getMessage());
            return false;
        }
    }
}

